﻿using S7.Net;
using System;

using S7.Net.Types;
using BaseUtils.Logger;

namespace DeviceManage.PLC
{
    public class SiemensS7
    {

        //private libnodave.daveOSserialType daveOSserialType;
        public Plc plc;

        //private libnodave.daveInterface daveInterface;
        //private int RackAddress = 2;

        //private int RackNumber = 0;

        public SiemensS7(CpuType cpuType, string IpAddress,int port, short Slot)
        {
            plc = new Plc(cpuType, IpAddress, port, 0, Slot);
            try
            {
                plc.Open();
            }
            catch (Exception ex)
            {
                LoggerService.Error($"PLC {IpAddress} :连接失败", ex);
            }
        }

        public void DisPlcConnect()
        {
            plc.Close();
        }

        public object ReadPlc(string DbAddress)
        {
            if (string.IsNullOrEmpty(DbAddress))
            {
                Console.WriteLine(3333333333);
            }
            DataType dataType;
            string[] Array = DbAddress.Split('.');
            int ReadBlock, ReadAddress;
            string BataType;
            object Result;
            if (!Array[0].StartsWith("DB"))
            {
                switch (Array[0].Substring(0, 1))
                {
                    case "I": dataType = DataType.Input; break;
                    case "Q": dataType = DataType.Output; break;
                    case "M": dataType = DataType.Memory; break;
                    default: throw new Exception("填写的地址格式错误，I\\Q\\M\\DB ??");
                }
                if (Array.Length == 1)
                {
                    ReadBlock = int.Parse(Array[0].Substring(2));
                    BataType = Array[0].Substring(1, 1);
                    ReadAddress = int.Parse(Array[0].Substring(2));
                    switch (BataType)
                    {
                        case "B": Result = Read<byte>(DbAddress); break;
                        case "W": Result = Read<ushort>(DbAddress); break;
                        case "D": Result = Read<int>(DbAddress); break;
                        case "F": Result = ReadPLCByFloat(dataType, ReadBlock, ReadAddress); break;
                        case "S": Result = ReadPLCByString(dataType, ReadBlock, ReadAddress, int.Parse(Array[2])); break;
                        default: throw new Exception("填写的地址格式错误，IB\\QW\\MD ??");
                    }
                    return Result;
                }
                else
                {
                    ReadBlock = int.Parse(Array[0].Substring(1));
                    ReadAddress = int.Parse(Array[0].Substring(1));
                    return Result = Read<bool>(DbAddress);
                    throw new Exception("填写的地址格式错误，I0.0\\Q100.7\\M55.5 ??");
                }

            }
            else if (Array[0].StartsWith("DB"))
            {
                dataType = DataType.DataBlock;
                ReadBlock = int.Parse(Array[0].Substring(2));
                BataType = Array[1].Substring(0, 3);
                ReadAddress = int.Parse(Array[1].Substring(3));
                switch (BataType)
                {
                    case "DBB": Result = Read<byte>(DbAddress); break;
                    case "DBW": Result = Read<ushort>(DbAddress); break;
                    case "DBD": Result = Read<uint>(DbAddress); break;
                    case "DBF": Result = ReadPLCByFloat(dataType, ReadBlock, ReadAddress); break;
                    case "DBS": Result = ReadPLCByString(dataType, ReadBlock, ReadAddress, int.Parse(Array[2])); break;
                    case "DBX": Result = Read<bool>(DbAddress); break;
                    default: throw new Exception("填写的DB数据格式错误，DBX\\DBB\\DBW\\DBD\\DBF\\DBS");
                }
                return Result;
            }
            throw new Exception("填写的地址格式错误，I\\Q\\M\\DB ??");
        }
        public T Read<T>(string address)
        {
            if (typeof(T) == typeof(float) && address.Contains("F"))
            {
                return (T)ReadPlc(address);
            }

            var obj = plc.Read(address);
            var value = (T)obj;
            return value;
        }
        private float ReadPLCByFloat(DataType dataType, int ReadBlock, int ReadAddress)
        {
            object value = plc.Read(dataType, ReadBlock, ReadAddress, VarType.Real, 1);
            return (float)value;
            //throw new Exception("无法读取PLC数值，错误码:" + Return);
        }
        private string ReadPLCByString(DataType dataType, int ReadBlock, int ReadAddress, int BytesToRead)
        {
            object value = plc.Read(DataType.DataBlock, ReadBlock, ReadAddress, VarType.String, BytesToRead);
            return (string)value;
            //byte[] array = new byte[BytesToRead];
            //Return = plc.readBytes((int)dataType, ReadBlock, ReadAddress, BytesToRead, array);
            //if (Return == 0)
            //{
            //    for (int i = 0; i < array.Length; i++)
            //    {
            //        if (array[i] < 37)
            //        {
            //            array[i] = 32;
            //        }
            //    }
            //    return Encoding.Default.GetString(array).Replace("\0", "");
            //}
            //throw new Exception("无法读取PLC数值，错误码:" + Return);
        }
        public void WritePlc(string DbAddress, object Value)
        {
            DataType dataType;
            string[] Array = DbAddress.Split(new char[] { '.' });
            int ReadBlock, ReadAddress;
            string BataType;
            if (Array[0].StartsWith("DB"))
            {
                dataType = DataType.DataBlock;
                ReadBlock = int.Parse(Array[0].Substring(2));
                BataType = Array[1].Substring(0, 3);
                ReadAddress = int.Parse(Array[1].Substring(3));
                switch (BataType)
                {
                    case "DBB": Write(DbAddress, Value); break;
                    case "DBW": Write(DbAddress, Value); break;
                    case "DBD": Write(DbAddress, Value); break;
                    case "DBF": WritePLCByFloat(dataType, ReadBlock, ReadAddress, float.Parse(Value.ToString())); break;
                    case "DBS": WritePLCByString(dataType, ReadBlock, ReadAddress, int.Parse(Array[2]), Value.ToString()); break;
                    case "DBX": Write(DbAddress, bool.Parse(Value.ToString())); break;
                    default: throw new Exception("填写的DB数据格式错误，DBX\\DBB\\DBW\\DBD\\DBF\\DBS");
                }
            }
            else
            {
                switch (Array[0].Substring(0, 1))
                {
                    case "I": dataType = DataType.Input; break;
                    case "Q": dataType = DataType.Output; break;
                    case "M": dataType = DataType.Memory; break;
                    default: throw new Exception("填写的地址格式错误，I\\Q\\M\\DB ??");
                }
                if (Array.Length == 1)
                {
                    ReadBlock = int.Parse(Array[0].Substring(2));
                    BataType = Array[0].Substring(1, 1);
                    ReadAddress = int.Parse(Array[0].Substring(2));
                    switch (BataType)
                    {
                        case "B":
                        case "W":
                        case "D": Write(DbAddress, Value); break;
                        case "F": WritePLCByFloat(dataType, ReadBlock, ReadAddress, float.Parse(Value.ToString())); break;// Result = ReadPLCByFloat(ReadBlock, ReadAddress); break;
                        case "S": WritePLCByString(dataType, ReadBlock, ReadAddress, int.Parse(Array[2]), Value.ToString()); break;//Write(DbAddress, Value); break;//Result = ReadPLCByString(ReadBlock, ReadAddress, int.Parse(Array[2])); break;
                        default: throw new Exception("填写的地址格式错误，IB\\QW\\MD ??");
                    }
                }
                else
                {
                    ReadBlock = int.Parse(Array[0].Substring(1));
                    ReadAddress = int.Parse(Array[0].Substring(1));
                    Write(DbAddress, bool.Parse(Value.ToString()));
                }
            }
        }
        public void Write<T>(string address, T value)
        {
            if ((value is float || value is double) && address.Contains("F"))
            {
                WritePlc(address, value);
            }
            else if (value is string && address.Contains("S"))
            {


                WritePlc(address, value);
            }
            else
            {
                plc.Write(address, value);
            }
        }

        private void WritePLCByFloat(DataType dataType, int ReadBlock, int ReadAddress, float value)
        {
            byte[] bytes = BitConverter.GetBytes(value);
            byte[] array = new byte[bytes.Length];
            for (int i = 0; i < bytes.Length; i++)
            {
                array[array.Length - i - 1] = bytes[i];
            }
            //Return = plc.writeBytes((int)dataType, ReadBlock, ReadAddress, 4, array);
            plc.WriteBytes(dataType, ReadBlock, ReadAddress, array);
            //if (Return != 0)
            //{
            //    throw new Exception("Could not WritePLCByFloat to PLC,Code:" + Return);
            //}
        }
        private void WritePLCByString(DataType dataType, int ReadBlock, int ReadAddress, int length, string value)
        {
            //byte[] bytes = Encoding.Default.GetBytes(value);
            //var b =  S7.Net.Types.String.ToByteArray(value,3);

            var b = S7String.ToByteArray(value, length);

            plc.Write(dataType, ReadBlock, ReadAddress, b);
            //plc.WriteBytes(dataType, ReadBlock, ReadAddress, bytes);

        }
        public int ReadClass(object obj, int db, int startAddr)
        {
            return plc.ReadClass(obj, db, startAddr);
        }
    }
    internal class Common
    {
        public static string IpAddress;
        public static int Slot;
        public static bool OffLineTest;
    }
}
